package com.lcm.basic.p6.gc.reference;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

/**
 * @author Coder-lcm
 * @date 2021/4/3
 *
 * 虚引用示例：
 *      虚引用通过 PhantomReference类实现,虚引用完全类似于没有引用。虚引用对对象本身没有太大
 * 影响,对象甚至感觉不到虚引用的存在。如果一个对象只有一个虚引用时,那它和没有引用的效果大
 * 致相同。虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和引用队列
 * (ReferenceQueue)联合使用。
 *      软引用和弱引用可以单独使用,但虚引用不能单独使用,单独使用虚引用没有太大的意义。虚引
 * 用的主要作用就是跟踪对象被垃圾回收的状态,程序可以通过检查与虚引用关联的引用队列中是否已
 * 经包含了该虚引用,从而了解虚引用所引用对象是否即将被回收。
 *
 *
 *      好处：
 *          使用这些引用类可以避免在程序执行期间将对象留在内存中。如果我们以软引用、弱引用或虚引
 *      用的方式引用对象,这样垃圾收集器就能够随意地释放对象。如果希望尽可能减小程序在其生命周期
 *      中所占用的内存大小时,这些引用类就很有好处。
 *          当然必须指出:要使用这些特殊的引用类,就不能保留对对象的强引用。如果保留了对对象的强
 *      引用,那么就会浪费这些类所提供的任何好处。
 */
public class PhantomReferenceDemo {
    public static void main(String[] args) {
        String str = new String("疯狂Java讲义");
        // 创建一个引用队列
        ReferenceQueue rq = new ReferenceQueue();
        //创建一个虚引用，让其虚引用到 “疯狂JAVA讲义“字符串对象
        WeakReference strPr = new WeakReference(str, rq);
        // 切断str与字符串”疯狂JAVA讲义“的引用。让 “疯狂Java讲义” 失活
        str = null;
        //尝试取出虚引用所引用的对象，这里并不能通过虚引用来访问被引用的的对象，所以此处为null
        System.out.println("虚引用对象: " + strPr.get());//null

        //强制进行gc
        System.gc();
        System.runFinalization();
        // 取出引用队列中最新进入队列的引用与pr进行比较
        System.out.println("引用队列首元素比较：" + (rq.poll() == strPr));//true
    }
}
